<?php

namespace Desktopd\MUA;


// POP3 client
class POP3Reception implements \IteratorAggregate, \ArrayAccess, \Countable {
    protected $messages = array();
    
    public function __construct (POP3Receiver $receiver, POP3Client $clientConfig) {
        $tcpClient = new TCPClient();
        if ($clientConfig->isPFSRequired()) {
            // PFS required
            $tcpClient->setCipherList(TCPClient::TLS_CIPHERS_SECURE);
        } elseif ($clientConfig->getCiphers()) {
            $tcpClient->setCipherList($clientConfig->getCiphers());
        }
        
        $flags = 0;
        if ($clientConfig->isInsecure()) $flags |= TCPClient::FLAG_TLS_INSECURE;
        if ($clientConfig->isTLSPort()) $flags |= TCPClient::FLAG_TLS_FULL;
        
        $host = $clientConfig->getHost();
        $port = $clientConfig->getPort();
        
        $tcpConnection = $tcpClient->createConnection($host, $port, $flags);
        $connection = new POP3Connection($tcpConnection);
        $connection->addDebugListener(function ($data) use ($receiver) {
            $receiver->callDebugger($data);
        });
        
        $checkTLS = function ($clientConfig, $tcpConnection) {
            $pinnedCert = $clientConfig->getPinnedCertificate();
            if ($pinnedCert) {
                if (!$tcpConnection->requireCertificate($pinnedCert)) {
                    throw new \RuntimeException(
                        'The server certificate does not match the pinned one'
                    );
                }
            }
        };
        
        if ($connection->isTLS()) {
            $checkTLS($clientConfig, $tcpConnection);
        }
        
        if (!$connection->readGreetings()) {
            throw new \RuntimeException('readGreetings(): failed');
        }
        
        if (!$connection->getCapabilities()) {
            throw new \RuntimeException('getCapabilities(): failed');
        }
        
        if ($clientConfig->isSTARTTLS() && (!$connection->isTLS())) {
            if (!$connection->startTLS()) {
                throw new \RuntimeException('STARTTLS: failed');
            }
            
            $checkTLS($clientConfig, $tcpConnection);
        }
        
        $user = $clientConfig->getUser();
        $password = $clientConfig->getPassword();
        
        if (!$connection->authenticate($user, $password)) {
            throw new \RuntimeException('Failed to authenticate');
        }
        
        $count = $connection->countMessages();
        if ($count === false) {
            throw new \RuntimeException('Failed to count messages');
        }
        
        for ($i = 1; $i <= $count; $i++) {
            $message = $connection->retrieveMessage($i);
            if (false === $message) {
                throw new \RuntimeException("Failed to retrieve the message #$i");
            }
            
            $this->messages[] = new ReceivedMessage($message);
            
            if (false === $connection->deleteMessage($i)) {
                throw new \RuntimeException("Failed to delete the message #$i");
            }
            
        }
        
        if (!$connection->quit()) {
            throw new \RuntimeException('Failed: quit()');
        }
    }
    
    public function getIterator () {
        return new \ArrayIterator($this->messages);
    }
    
    public function offsetExists ($offset) {
        return isset($this->messages[$offset]);
    }
    
    public function offsetGet ($offset) {
        return isset($this->messages[$offset]) ? $this->messages[$offset] : null;
    }
    
    public function offsetSet ($offset, $value) {
        // NOOP
    }
    
    public function offsetUnset ($offset) {
        // NOOP
    }
    
    public function count () {
        return count($this->messages);
    }
}


// vim: ts=4 et ai

